#include "VulkanPixelObjectGlobal.h"
#include "Render/VulkanContext.h"

#include "Render/Material/VulkanShaders.h"
#include "Render/Material/VulkanShader.h"

void CVulkanPixelObjectGlobal::Init()
{
    CreateRenderPass();
    CreateDescriptorLayout();
    CreatePipelineLayout();
    CreatePipeline();

}

CVulkanPixelObjectGlobal *CVulkanPixelObjectGlobal::Create()
{
    auto Result=new CVulkanPixelObjectGlobal();
    Result->Init();
    return Result;
}

CVulkanPixelObjectGlobal *CVulkanPixelObjectGlobal::Get()
{
    static CVulkanPixelObjectGlobal* Instance=Create();
    return Instance;
}

void CVulkanPixelObjectGlobal::CreateRenderPass()
{
    //创建渲染通道
    //只需要一个uint16_t的颜色附件,和一个深度附件
    //颜色附件仅仅用于存储像素对象的ID
    vk::AttachmentDescription ColorAttachment = {};
    ColorAttachment.format = vk::Format::eR16Uint;
    ColorAttachment.samples = vk::SampleCountFlagBits::e1;
    ColorAttachment.loadOp = vk::AttachmentLoadOp::eClear;
    ColorAttachment.storeOp = vk::AttachmentStoreOp::eStore;
    ColorAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
    ColorAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
    ColorAttachment.initialLayout = vk::ImageLayout::eUndefined;
    ColorAttachment.finalLayout = vk::ImageLayout::eColorAttachmentOptimal;

    vk::AttachmentDescription DepthAttachment = {};
    DepthAttachment.format = vk::Format::eD32Sfloat;
    DepthAttachment.samples = vk::SampleCountFlagBits::e1;
    DepthAttachment.loadOp = vk::AttachmentLoadOp::eClear;
    DepthAttachment.storeOp = vk::AttachmentStoreOp::eDontCare;
    DepthAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
    DepthAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
    DepthAttachment.initialLayout = vk::ImageLayout::eUndefined;
    DepthAttachment.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;

    vk::AttachmentReference ColorAttachmentRef = {};
    ColorAttachmentRef.attachment = 0;
    ColorAttachmentRef.layout = vk::ImageLayout::eColorAttachmentOptimal;

    vk::AttachmentReference DepthAttachmentRef = {};
    DepthAttachmentRef.attachment = 1;
    DepthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;

    vk::SubpassDescription Subpass = {};
    Subpass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
    Subpass.colorAttachmentCount = 1;
    Subpass.pColorAttachments = &ColorAttachmentRef;
    Subpass.pDepthStencilAttachment = &DepthAttachmentRef;

    vk::SubpassDependency Dependency = {};
    Dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    Dependency.dstSubpass = 0;
    Dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
    Dependency.srcAccessMask = vk::AccessFlagBits::eNoneKHR;
    Dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
    Dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;

    TVector<vk::AttachmentDescription> Attachments = {
        ColorAttachment
        , DepthAttachment};

    vk::RenderPassCreateInfo RenderPassInfo = {};
    RenderPassInfo.attachmentCount = Attachments.Num();
    RenderPassInfo.pAttachments = Attachments.Data();
    RenderPassInfo.subpassCount = 1;
    RenderPassInfo.pSubpasses = &Subpass;
    RenderPassInfo.dependencyCount = 1;
    RenderPassInfo.pDependencies = &Dependency;

    RenderPass = CVulkanContext::Get()->GetDevice()
        .createRenderPass(RenderPassInfo);
}

void CVulkanPixelObjectGlobal::CreateDescriptorLayout()
{
    //需要两个uniform buffer
    //一个是模型矩阵 和 ObjectID
    //一个是视角信息

    //创建描述符布局
    vk::DescriptorSetLayoutBinding ModelMatrixBinding;
    ModelMatrixBinding.binding = 0;
    ModelMatrixBinding.descriptorType = vk::DescriptorType::eUniformBuffer;
    ModelMatrixBinding.descriptorCount = 1;
    ModelMatrixBinding.stageFlags = vk::ShaderStageFlagBits::eVertex;
    ModelMatrixBinding.pImmutableSamplers = nullptr;

    DescriptorLayout.Layout =
        CVulkanContext::Get()->GetDevice().createDescriptorSetLayout(
            vk::DescriptorSetLayoutCreateInfo()
            .setBindingCount(1)
            .setPBindings(&ModelMatrixBinding)
        );
    DescriptorLayout.DescriptorNums.UniformBufferDescriptorNum=1;
    

    //视角信息
    vk::DescriptorSetLayoutBinding ViewMatrixBinding;
    ViewMatrixBinding.binding = 0;
    ViewMatrixBinding.descriptorType = vk::DescriptorType::eUniformBuffer;
    ViewMatrixBinding.descriptorCount = 1;
    ViewMatrixBinding.stageFlags = vk::ShaderStageFlagBits::eVertex;

    ViewDescriptorLayout.Layout =
        CVulkanContext::Get()->GetDevice().createDescriptorSetLayout(
            vk::DescriptorSetLayoutCreateInfo()
            .setBindingCount(1)
            .setPBindings(&ViewMatrixBinding)
        );
    
    ViewDescriptorLayout.DescriptorNums.UniformBufferDescriptorNum=1;
}

void CVulkanPixelObjectGlobal::CreatePipelineLayout()
{

    vk::DescriptorSetLayout Layouts[] = {
        DescriptorLayout.Layout,
        ViewDescriptorLayout.Layout
    };

    vk::PipelineLayoutCreateInfo PipelineLayoutInfo = {};
    PipelineLayoutInfo.setLayoutCount = 2;
    PipelineLayoutInfo.pSetLayouts = Layouts;
    PipelineLayoutInfo.pushConstantRangeCount = 0;
    PipelineLayoutInfo.pPushConstantRanges = nullptr;

    PipelineLayout = CVulkanContext::Get()->GetDevice().createPipelineLayout(PipelineLayoutInfo);
}

void CVulkanPixelObjectGlobal::CreatePipeline()
{
    //创建并注册着色器
    std::shared_ptr<CVulkanShader> VertexShader;
    {
        TVector<uint8_t> ShaderData={
            #include "Shaders/PixelObject/PixelObject.vert.spv.h"
        };
        VertexShader=CVulkanShaders::CreateShaderFromRaw(ShaderData,vk::ShaderStageFlagBits::eVertex);
        CVulkanContext::Get()->GetShaderManager()->RegisterVulkanOnlyShader(U"PixelObjectVertex",VertexShader);
    }

    std::shared_ptr<CVulkanShader> FragmentShader;
    {
        TVector<uint8_t> ShaderData={
            #include "Shaders/PixelObject/PixelObject.frag.spv.h"
        };
        FragmentShader=CVulkanShaders::CreateShaderFromRaw(ShaderData,vk::ShaderStageFlagBits::eFragment);
        CVulkanContext::Get()->GetShaderManager()->RegisterVulkanOnlyShader(U"PixelObjectFragment",FragmentShader);
    }

    //创建管线
    vk::PipelineShaderStageCreateInfo ShaderStages[2] = {};
    ShaderStages[0].stage = vk::ShaderStageFlagBits::eVertex;
    ShaderStages[0].module = VertexShader->Module;
    ShaderStages[0].pName = "main";
    ShaderStages[1].stage = vk::ShaderStageFlagBits::eFragment;
    ShaderStages[1].module = FragmentShader->Module;
    ShaderStages[1].pName = "main";

    auto VertexInputBindingDescriptions=
        CVulkanContext::Get()->GetMeshVertexInputBindingDescriptions();

    auto VertexInputAttributeDescription=
        CVulkanContext::Get()->GetMeshVertexInputAttributeDescriptions();

    vk::PipelineVertexInputStateCreateInfo PipelineVertexInputStateCreateInfo=vk::PipelineVertexInputStateCreateInfo()
        .setVertexBindingDescriptionCount(VertexInputBindingDescriptions.Num())
        .setPVertexBindingDescriptions(VertexInputBindingDescriptions.Data())
        .setVertexAttributeDescriptionCount(VertexInputAttributeDescription.Num())
        .setPVertexAttributeDescriptions(VertexInputAttributeDescription.Data());

    vk::PipelineInputAssemblyStateCreateInfo PipelineInputAssemblyStateCreateInfo=vk::PipelineInputAssemblyStateCreateInfo()
        .setTopology(vk::PrimitiveTopology::eTriangleList)
        .setPrimitiveRestartEnable(false);

    //动态状态
    vk::DynamicState DynamicStates[] = {
        vk::DynamicState::eViewport,
        vk::DynamicState::eScissor
    };

    vk::PipelineDynamicStateCreateInfo DynamicStateCreateInfo = vk::PipelineDynamicStateCreateInfo()
        .setDynamicStateCount(2)
        .setPDynamicStates(DynamicStates);

    vk::PipelineViewportStateCreateInfo ViewportStateCreateInfo = vk::PipelineViewportStateCreateInfo()
        .setViewportCount(1)
        .setScissorCount(1);

    vk::PipelineRasterizationStateCreateInfo RasterizationStateCreateInfo = vk::PipelineRasterizationStateCreateInfo()
        .setDepthClampEnable(false)
        .setRasterizerDiscardEnable(false)
        .setPolygonMode(vk::PolygonMode::eFill)
        .setLineWidth(1.0f)
        .setCullMode(vk::CullModeFlagBits::eBack)
        .setFrontFace(vk::FrontFace::eCounterClockwise)
        .setDepthBiasEnable(false);

    vk::PipelineMultisampleStateCreateInfo MultisampleStateCreateInfo = vk::PipelineMultisampleStateCreateInfo()
        .setSampleShadingEnable(false)
        .setRasterizationSamples(vk::SampleCountFlagBits::e1);

    vk::PipelineDepthStencilStateCreateInfo DepthStencilStateCreateInfo = vk::PipelineDepthStencilStateCreateInfo()
        .setDepthTestEnable(true)
        .setDepthWriteEnable(true)
        .setDepthCompareOp(vk::CompareOp::eLess)
        .setDepthBoundsTestEnable(false)
        .setStencilTestEnable(false);

    vk::PipelineColorBlendAttachmentState ColorBlendAttachmentState = vk::PipelineColorBlendAttachmentState()
        .setColorWriteMask(vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA)
        .setBlendEnable(false);

    vk::PipelineColorBlendStateCreateInfo ColorBlendStateCreateInfo = vk::PipelineColorBlendStateCreateInfo()
        .setLogicOpEnable(false)
        .setLogicOp(vk::LogicOp::eCopy)
        .setAttachmentCount(1)
        .setPAttachments(&ColorBlendAttachmentState);

    vk::GraphicsPipelineCreateInfo PipelineCreateInfo = vk::GraphicsPipelineCreateInfo()
        .setStageCount(2)
        .setPStages(ShaderStages)
        .setPVertexInputState(&PipelineVertexInputStateCreateInfo)
        .setPInputAssemblyState(&PipelineInputAssemblyStateCreateInfo)
        .setPViewportState(&ViewportStateCreateInfo)
        .setPRasterizationState(&RasterizationStateCreateInfo)
        .setPMultisampleState(&MultisampleStateCreateInfo)
        .setPDepthStencilState(&DepthStencilStateCreateInfo)
        .setPColorBlendState(&ColorBlendStateCreateInfo)
        .setLayout(PipelineLayout)
        .setRenderPass(RenderPass)
        .setSubpass(0)
        .setPDynamicState(&DynamicStateCreateInfo);

    Pipeline =CVulkanContext::Get()->GetDevice().createGraphicsPipeline(
        nullptr,
        PipelineCreateInfo
    ).value;
    

    
}
